//
// Created on 2024/4/21.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include "thread_gfx.h"
#include <asm-generic/stat.h>
#include <thread>
#include <unistd.h>
#include <atomic>
#include <string>
#include <native_vsync/native_vsync.h>
#include "Export/export.h"
#include "gles/glesshader.h"

#include "thread/thread.h"
#include "mlog.h"

//static std::atomic<bool> vsync;
static sem_t vsync_sem;
static OH_NativeVSync *syncobj;
static glesmain *glesmain_;
struct Color {
public:
    float r;
    float g;
    float b;
    float a;
};
static Color _clearcolor;
const EGLint CONTEXT_ATTRIBS[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
static void OnSync(long long timestamp, void *data) {
    sem_post(&vsync_sem);//发射信号
    //vsync = true;
}
static void GFX_Init() {
    {
        // Create context.
        glesmain_->m_eglContext_gfx =
            eglCreateContext(glesmain_->m_eglDisplay, glesmain_->m_eglConfig, EGL_NO_CONTEXT, CONTEXT_ATTRIBS);
        int err4 = eglGetError();
        MLOGFormat("eglCreateContext %{public}d %{public}04x", glesmain_->m_eglContext_gfx, err4);

        if (!eglMakeCurrent(glesmain_->m_eglDisplay, glesmain_->m_eglSurface, glesmain_->m_eglSurface,
                            glesmain_->m_eglContext_gfx)) {
            int err = eglGetError();
            auto errstr = eglQueryString(glesmain_->m_eglDisplay, err);
            // 3006 EGL_BAD_CONTEXT
            MERRORFormat("eglMakeCurrent failed %{public}04x %{public}s", err, errstr);
            return;
        }

        const char *ptrver = (const char *)glGetString(GL_VERSION);
        MLOGFormat("===GLVersion %{public}s", ptrver);
        // Create program.
        //    program_ = CreateProgram(VERTEX_SHADER, FRAGMENT_SHADER);
        //    if (program_ == PROGRAM_ERROR) {
        //        MERROR("CreateProgram: unable to create program");
        //        return ;
        //    }
        glViewport(0, 0, glesmain_->width, glesmain_->height);
        _clearcolor.r = 1.0f;
        _clearcolor.g = 0;
        _clearcolor.b = 0.5f;
        _clearcolor.a = 1;


    }
}
static int fcount=0;
static void GFX_Frame() {
    fcount++;
    if(fcount%100==0)
        MLOGFormat("GFX_Frame %{public}d", fcount);

    //用寄存器给他发数据
    GetCallBackData(UpdateFrame).reg_data[0] =1;
    GetCallBackData(UpdateFrame).reg_data[1] = fcount;


    DispatchEvent(UpdateFrame);
    // 但是ArkTS 的线程问题还没弄清楚,非主线程直接搞是很危险的
    // 这个事件将直接在本线程执行
    // 否则可能会导致ArkTS 无响应

    _clearcolor.r += 0.01f;
    _clearcolor.g += 0.01f;
    _clearcolor.b += 0.01f;
    if (_clearcolor.r > 1.0f)
        _clearcolor.r = 0;
    if (_clearcolor.g > 1.0f)
        _clearcolor.g = 0;
    if (_clearcolor.b > 1.0f)
        _clearcolor.b = 0;

    glClearColor(_clearcolor.r, _clearcolor.g, _clearcolor.b, _clearcolor.a);
    glClear(GL_COLOR_BUFFER_BIT);
    glFlush();
    //glFinish();
    eglSwapBuffers(glesmain_->m_eglDisplay, glesmain_->m_eglSurface);
}
static void GFX_Loop() {
    auto t = getThreadID();
    MLOGFormat("GFX_Loop thread=%{public}16x", t);


    //vsync = false;
    std::string name = "render_vsync";
    syncobj = OH_NativeVSync_Create(name.c_str(), name.length());

    GFX_Init();
    sem_post(&glesmain_->sem_gfx_init); // 发射初始化信号
    while (true) {
        OH_NativeVSync_RequestFrame(syncobj, OnSync, nullptr);

        sem_wait(&vsync_sem);//等待信号量，比Sleep 机制要平滑的得多，linux 的sleep？为啥如此？
        //while (vsync == false) { usleep(1000); }

        GFX_Frame();
    }
}
void Start_Thread_Gfx(glesmain *pglesmain) {
    glesmain_ = pglesmain;


    std::thread *thread = new std::thread(GFX_Loop);
}